package com.googlecode.jot.translators;

import java.lang.reflect.Type;

import com.googlecode.jot.AbstractTypeTranslator;
import com.googlecode.jot.ReflectionUtil;
import com.googlecode.jot.TranslationContext;
import com.googlecode.jot.TranslationHints;

/**
 * {@link TypeTranslator} for primitive types.  This {@link TypeTranslator}
 * passes through {@link Boolean}, {@link Character} and {@link String} types
 * without modifying them.  Numberic types are converted based on the
 * {@code desiredType} argument passed to {@link #translateToLocal(Object, TranslationContext, Type, TranslationHints)}.
 * When translating from local all values are just passed through.
 *
 */
public class PrimitiveTypeTranslator
	extends AbstractTypeTranslator<Object, Object> {

	/**
	 * Creates the translator.
	 */
	public PrimitiveTypeTranslator() {
		super.addSupportedLocalClass(Byte.class);
		super.addSupportedLocalClass(Short.class);
		super.addSupportedLocalClass(Integer.class);
		super.addSupportedLocalClass(Long.class);
		super.addSupportedLocalClass(Float.class);
		super.addSupportedLocalClass(Double.class);
		super.addSupportedLocalClass(Boolean.class);
		super.addSupportedLocalClass(Character.class);
		super.addSupportedLocalClass(String.class);
	}

	/**
	 * {@inheritDoc}
	 */
	public Object translateFromLocal(Object local, TranslationContext converter, TranslationHints hints) {
		return local;
	}

	/**
	 * {@inheritDoc}
	 */
	public Object translateToLocal(
		Object object, TranslationContext converter, Type desiredType, TranslationHints hints) {
		// get class
		Class<?> desiredClass = ReflectionUtil.clazz(desiredType);

		// handle numbers
		if (Number.class.isAssignableFrom(desiredClass)) {
			Number number = Number.class.cast(object);
			if (desiredClass.equals(Byte.class)) {
				return number.byteValue();
			} else if (desiredClass.equals(Short.class)) {
				return number.shortValue();
			} else if (desiredClass.equals(Integer.class)) {
				return number.intValue();
			} else if (desiredClass.equals(Long.class)) {
				return number.longValue();
			} else if (desiredClass.equals(Float.class)) {
				return number.floatValue();
			} else if (desiredClass.equals(Double.class)) {
				return number.doubleValue();
			}

		// booleans
		} else if (Boolean.class.isAssignableFrom(desiredClass)) {
			return new Boolean(object.toString());
		}

		// handle the others
		return object;
	}

}
